package hotel.common;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.function.UnaryOperator;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.util.StringConverter;
import javafx.util.converter.IntegerStringConverter;
import javafx.util.converter.NumberStringConverter;

public class Comm {
	
	public static TextFormatter<Integer> getIntFormatter(int defaultValue) {
		NumberFormat intFormat = NumberFormat.getIntegerInstance();
		TextFormatter<Integer> intFormatter = new TextFormatter<Integer>(
		        new IntegerStringConverter(), defaultValue, getNumberFormatterFilter(intFormat));
		return intFormatter;
	}
	
	public static TextFormatter<Number> getDecimalFormatter(double defaultValue) {
		DecimalFormat format = new DecimalFormat( "#.00" );
		TextFormatter<Number> intFormatter = new TextFormatter<Number>(
		        new NumberStringConverter(), defaultValue, getNumberFormatterFilter(format));
		return intFormatter;
	}
	
	public static TextFormatter<Number> getDecimalFormatter() {
		DecimalFormat format = new DecimalFormat( "#.00" );
		TextFormatter<Number> intFormatter = new TextFormatter<Number>(getNumberFormatterFilter(format));
		return intFormatter;
	}
	
	public static TextFormatter<Number> getNegativeDecimalFormatter() {
		DecimalFormat format = new DecimalFormat( "#.00;-#.00" );
		TextFormatter<Number> intFormatter = new TextFormatter<Number>(getNumberFormatterFilter(format));
		return intFormatter;
	}
	
	private static UnaryOperator<TextFormatter.Change> getNumberFormatterFilter(NumberFormat format) {
		UnaryOperator<TextFormatter.Change> filter = c -> {
		    if (c.isContentChange()) {
		        ParsePosition parsePosition = new ParsePosition(0);
		        // NumberFormat evaluates the beginning of the text
		        format.parse(c.getControlNewText(), parsePosition);
		        if (parsePosition.getIndex() == 0 ||
		                parsePosition.getIndex() < c.getControlNewText().length()) {
		            // reject parsing the complete text failed
		            return null;
		        }
		    }
		    return c;
		};
		return filter;
	}
	
	public static ChangeListener<String> getNumberTextFieldListener(TextField tf) {
		return new ChangeListener<String>() {
			@Override
			public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
				if (!newValue.matches("\\d*")) {
					tf.setText(newValue.replaceAll("[^\\d]", ""));
				}
			}
		};
	}
	
	/**
	 * c&p from Spinner
	 */
	public static <T> void commitEditorText(Spinner<T> spinner) {
	    if (!spinner.isEditable()) return;
	    String text = spinner.getEditor().getText();
	    SpinnerValueFactory<T> valueFactory = spinner.getValueFactory();
	    if (valueFactory != null) {
	        StringConverter<T> converter = valueFactory.getConverter();
	        if (converter != null) {
	            T value = converter.fromString(text);
	            valueFactory.setValue(value);
	        }
	    }
	}

}
